/*
 * Copyright (C) 2019 Peng fei Pan <panpfpanpf@outlook.me>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package me.panpf.sketch.decode;

import me.panpf.sketch.ErrorTracker;
import me.panpf.sketch.HiLog;
import me.panpf.sketch.cache.BitmapPool;
import me.panpf.sketch.cache.BitmapPoolUtils;
import me.panpf.sketch.cache.DiskCache;
import me.panpf.sketch.datasource.DataSource;
import me.panpf.sketch.datasource.DiskCacheDataSource;
import me.panpf.sketch.datasource.FileDataSource;
import me.panpf.sketch.request.LoadRequest;
import me.panpf.sketch.request.MaxSize;
import me.panpf.sketch.util.Log;
import me.panpf.sketch.util.SketchUtils;
import me.panpf.sketch.zoom.PixmapBuild;
import ohos.agp.utils.Rect;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;


@SuppressWarnings("WeakerAccess")
public class ImageDecodeUtils {

    /**
     * 解码位图
     *
     * @param dataSource 位图数据来源
     * @param options    位图解码选项
     * @return 能创建位图的对象
     * @throws IOException
     */
    public static PixmapBuild decodeBitmap(DataSource dataSource, ImageSource.DecodingOptions options) throws IOException {
        InputStream inputStream = null;
        PixmapBuild bitmap;

        try {
            ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
            inputStream = dataSource.getInputStream();
            ImageSource source = ImageSource.create(inputStream, sourceOptions);
            options.editable = true;
            bitmap = new PixmapBuild(source, options);
        } finally {
            SketchUtils.close(inputStream);
        }
        return bitmap;
    }

    /**
     * 解码位图
     *
     * @param dataSource 位图数据来源
     * @param options    位图解码选项
     * @return 位图
     * @throws IOException
     */
    public static PixelMap decodeBitmap(DataSource dataSource, ImageSource.SourceOptions options) throws IOException {
        InputStream inputStream = null;
        PixelMap bitmap;

        try {
            inputStream = dataSource.getInputStream();
            ImageSource source = ImageSource.create(inputStream, options);
            bitmap = source.createPixelmap(null);
        } finally {
            SketchUtils.close(inputStream);
        }

        return bitmap;
    }

    /**
     * 解码区域图片
     *
     * @param dataSource 位图数据来源
     * @param srcRect    位图矩形区域
     * @param options    位图解码选项
     * @return PixmapBuild 能创建位图的对象
     */
    public static PixmapBuild decodeRegionBitmap(DataSource dataSource, Rect srcRect, ImageSource.DecodingOptions options) {
        InputStream inputStream;
        try {
            inputStream = dataSource.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

//        BitmapRegionDecoder regionDecoder;
//        try {
//            regionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
//        } catch (IOException e) {
//            e.printStackTrace();
//            return null;
//        } finally {
//            SketchUtils.close(inputStream);
//        }
        ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
        ImageSource source = ImageSource.create(inputStream, sourceOptions);
        source.getImageInfo().size.width = srcRect.getWidth();
        source.getImageInfo().size.height = srcRect.getHeight();
        SketchUtils.close(inputStream);
        return new PixmapBuild(source, options);
    }

    /**
     * 解码图片成功
     * @param bitmap
     * @param outWidth
     * @param outHeight
     * @param inSampleSize
     * @param loadRequest
     * @param logName
     */
    static void decodeSuccess(PixmapBuild bitmap, int outWidth, int outHeight, int inSampleSize, LoadRequest loadRequest, String logName) {
        if (loadRequest.getOptions().getMaxSize() != null) {
           } else {
            HiLog.debug("Decode bitmap. bitmapSize=%dx%d. %s", bitmap.getPixelMap().getImageInfo().size.width, bitmap.getPixelMap().getImageInfo().size.height, loadRequest.getKey());
        }
    }

    /**
     * 解码图片失败
     * @param request
     * @param dataSource
     * @param logName
     * @param cause
     * @param tr
     */
    static void decodeError(LoadRequest request, DataSource dataSource, String logName, String cause, Throwable tr) {
        if (tr != null) {
//            SLog.e(logName, Log.getStackTraceString(tr));
        }

        if (dataSource instanceof DiskCacheDataSource) {
            DiskCache.Entry diskCacheEntry = ((DiskCacheDataSource) dataSource).getDiskCacheEntry();
            File cacheFile = diskCacheEntry.getFile();
            if (diskCacheEntry.delete()) {
                HiLog.error("Decode failed. %s. Disk cache deleted. fileLength=%d. %s", cause, cacheFile.length(), request.getKey(), tr);
            } else {
                HiLog.error("Decode failed. %s. Disk cache can not be deleted. fileLength=%d. %s", cause, cacheFile.length(), request.getKey());
            }
        } else if (dataSource instanceof FileDataSource) {
            File file = ((FileDataSource) dataSource).getFile(null, null);
            //noinspection ConstantConditions
            HiLog.error("Decode failed. %s. filePath=%s, fileLength=%d. %s",
                    cause, file.getPath(), file.exists() ? file.length() : -1, request.getKey());
        } else {
            HiLog.error("Decode failed. %s. %s", cause, request.getUri());
        }
    }

    /**
     * 通过异常类型以及 message 确定是不是由 inBitmap 导致的解码失败
     * @param throwable
     * @param options
     * @param fromBitmapRegionDecoder
     * @return boolean
     */
    public static boolean isInBitmapDecodeError(Throwable throwable, ImageSource.DecodingOptions options, boolean fromBitmapRegionDecoder) {
        if (fromBitmapRegionDecoder && !BitmapPoolUtils.sdkSupportInBitmapForRegionDecoder()) {
            return false;
        }

        if (!(throwable instanceof IllegalArgumentException)) {
            return false;
        }

//        if (options.inBitmap == null) {
//            return false;
//        }

        String message = throwable.getMessage();
        return message != null && (message.equals("Problem decoding into existing bitmap") || message.contains("bitmap"));
    }

    /**
     * 反馈 inBitmap 解码失败，并回收 inBitmap
     * @param errorTracker
     * @param bitmapPool
     * @param imageUri
     * @param imageWidth
     * @param imageHeight
     * @param imageMimeType
     * @param throwable
     * @param decodeOptions
     * @param fromBitmapRegionDecoder
     */
    public static void recycleInBitmapOnDecodeError(ErrorTracker errorTracker, BitmapPool bitmapPool,
                                                    String imageUri, int imageWidth, int imageHeight, String imageMimeType,
                                                    Throwable throwable, ImageSource.DecodingOptions decodeOptions, boolean fromBitmapRegionDecoder) {
        if (fromBitmapRegionDecoder && !BitmapPoolUtils.sdkSupportInBitmapForRegionDecoder()) {
            return;
        }

        errorTracker.onInBitmapDecodeError(imageUri, imageWidth, imageHeight, imageMimeType, throwable, decodeOptions.sampleSize, null);

//        BitmapPoolUtils.freeBitmapToPool(decodeOptions.inBitmap, bitmapPool);
//        decodeOptions.inBitmap = null;
    }

    /**
     * 通过异常类型以及 message 确定是不是由 srcRect 导致的解码失败
     * @param throwable
     * @param imageWidth
     * @param imageHeight
     * @param srcRect
     * @return boolean
     */
    public static boolean isSrcRectDecodeError(Throwable throwable, int imageWidth, int imageHeight, Rect srcRect) {
        if (!(throwable instanceof IllegalArgumentException)) {
            return false;
        }

        if (srcRect.left < imageWidth || srcRect.top < imageHeight || srcRect.right > imageWidth || srcRect.bottom > imageHeight) {
            return true;
        }

        String message = throwable.getMessage();
        return message != null && (message.equals("rectangle is outside the image srcRect") || message.contains("srcRect"));
    }
}
